package com.alibaba.algo.cooperation.service.impl;

import com.alibaba.algo.cooperation.config.CaffeineConfig;
import com.alibaba.algo.cooperation.config.DingTalkConstants;
import com.alibaba.algo.cooperation.service.DingTalkService;
import com.alibaba.algo.cooperation.entity.dto.res.DingTalkUserResDTO;
import com.alibaba.algo.cooperation.utils.StringUtil;
import com.alibaba.fastjson.JSON;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.request.OapiSnsGetuserinfoBycodeRequest;
import com.dingtalk.api.request.OapiUserGetbyunionidRequest;
import com.dingtalk.api.request.OapiV2UserGetRequest;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.dingtalk.api.response.OapiSnsGetuserinfoBycodeResponse;
import com.dingtalk.api.response.OapiUserGetbyunionidResponse;
import com.dingtalk.api.response.OapiV2UserGetResponse;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

/**
 * @ClassName DingTalkServiceImpl
 * @Description 钉钉应用实现类
 * @Author wangke
 * @Date 2021/9/17 16:12
 */
@Slf4j
@Service
public class DingTalkServiceImpl implements DingTalkService {

    @Override
    public DingTalkUserResDTO getUserGetResponse(String code, String appkey, String appSecret) {
        return getUserGetResponseNew(code,appkey,appSecret,DingTalkConstants.BASE_URL);
    }

    @Override
    public DingTalkUserResDTO getUserGetResponseNew(String code, String appkey, String appSecret, String baseUrl) {
        DingTalkUserResDTO dingTalkUserResDTO = new DingTalkUserResDTO();
        if (StringUtil.isEmptyAny(appkey, appSecret)) {
            return null;
        }
        // 处理基础Url
        if(StringUtil.isEmpty(baseUrl)){
            baseUrl = DingTalkConstants.BASE_URL;
        }
        // 获取钉钉unionid
        String unionid = getUnionid(code, appkey, appSecret, baseUrl);
        if (StringUtil.isEmpty(unionid)) {
            return null;
        }
        // 获取接口调用凭证
        String dingToken = getToken(appkey, appSecret, baseUrl);
        if (StringUtil.isEmpty(dingToken)) {
            return null;
        }
        // 获取钉钉用户id
        String dingUserId = getUserId(unionid, dingToken, baseUrl);
        if (StringUtil.isEmpty(dingUserId)) {
            return null;
        }

        // 钉钉用户信息
        OapiV2UserGetResponse.UserGetResponse userGetResponse = getDingdingUserResponse(dingUserId, dingToken, baseUrl);
        log.info("钉钉用户标识：{},钉钉用户信息：{}", dingUserId, JSON.toJSONString(userGetResponse));

        if(!ObjectUtils.isEmpty(userGetResponse)){
            dingTalkUserResDTO.setDingUserName((ObjectUtils.isEmpty(userGetResponse.getName()) ? null : userGetResponse.getName()));
            dingTalkUserResDTO.setDingUserId((ObjectUtils.isEmpty(dingUserId) ? null : dingUserId));
            dingTalkUserResDTO.setMobileNum((ObjectUtils.isEmpty(userGetResponse.getMobile()) ? null : userGetResponse.getMobile()));
            dingTalkUserResDTO.setEmail((ObjectUtils.isEmpty(userGetResponse.getEmail()) ? null : userGetResponse.getEmail()));
        }
        return dingTalkUserResDTO;
    }

    /**
     * @Description: 获取钉钉接口token(access_token的有效期为7200秒（2小时）)
     */
    private String getToken(String appkey, String appSecret, String baseUrl) {
        String cacheTokenKey = DingTalkConstants.LOCAL_CACHE_TOKEN_KEY_PRFIX + appkey;
        String token = CaffeineConfig.caffeineCache.getIfPresent(cacheTokenKey);
        if (StringUtil.isNotEmpty(token)) {
            return token;
        }
        DingTalkClient client = new DefaultDingTalkClient(baseUrl+DingTalkConstants.GET_TOKEN);
        OapiGettokenRequest request = new OapiGettokenRequest();
        request.setAppkey(appkey);
        request.setAppsecret(appSecret);
        request.setHttpMethod(DingTalkConstants.HTTP_METHOD_GET);
        try {
            OapiGettokenResponse response = client.execute(request);
            if (response != null && DingTalkConstants.RESPONSE_SUCCESS_CODE.equals(response.getErrorCode())) {
                token = response.getAccessToken();
                CaffeineConfig.caffeineCache.put(cacheTokenKey,token);
            }
        } catch (ApiException e) {
            log.error("获取钉钉接口调用凭证出错", e);
        }
        return token;
    }

    private String getUnionid(String code, String appkey, String appSecret, String baseUrl) {
        String unionid = null;
        // 通过临时授权码获取授权用户的个人信息
        DefaultDingTalkClient client = new DefaultDingTalkClient(baseUrl+DingTalkConstants.GET_BY_CODE);
        OapiSnsGetuserinfoBycodeRequest reqBycodeRequest = new OapiSnsGetuserinfoBycodeRequest();
        // 通过扫描二维码，跳转指定的redirect_uri后，向url中追加的code临时授权码
        reqBycodeRequest.setTmpAuthCode(code);
        try {
            OapiSnsGetuserinfoBycodeResponse bycodeResponse = client.execute(reqBycodeRequest, appkey, appSecret);
            if (bycodeResponse != null && bycodeResponse.isSuccess() && DingTalkConstants.RESPONSE_SUCCESS_CODE.equals(bycodeResponse.getErrorCode())) {
                unionid = bycodeResponse.getUserInfo().getUnionid();
            }
        } catch (ApiException e) {
            log.error("获取钉钉用户标识失败：{}", e);
        }
        return unionid;
    }

    /**
     * @Description: 获取钉钉用户标识
     * @param: unionid
     * @param: token
     */
    private String getUserId(String unionid, String token, String baseUrl) {
        String userId = null;
        // 根据unionid获取userid
        DingTalkClient clientDingTalkClient = new DefaultDingTalkClient(baseUrl+DingTalkConstants.GET_BY_UNION_ID);
        OapiUserGetbyunionidRequest reqGetbyunionidRequest = new OapiUserGetbyunionidRequest();
        reqGetbyunionidRequest.setUnionid(unionid);
        try {
            OapiUserGetbyunionidResponse oapiUserGetbyunionidResponse = clientDingTalkClient.execute(reqGetbyunionidRequest, token);
            log.info("oapiUserGetbyunionidResponse:{}", JSON.toJSONString(oapiUserGetbyunionidResponse));
            if (oapiUserGetbyunionidResponse != null && oapiUserGetbyunionidResponse.isSuccess() && DingTalkConstants.RESPONSE_SUCCESS_CODE.equals(oapiUserGetbyunionidResponse.getErrorCode())) {
                userId = oapiUserGetbyunionidResponse.getResult().getUserid();
            }
        } catch (ApiException e) {
            log.error("获取钉钉用户标识失败：{}", e);
        }
        return userId;
    }

    /**
     * @Description: 获取钉钉用户信息
     * @param: userId
     */
    private OapiV2UserGetResponse.UserGetResponse getDingdingUserResponse(String userId, String token, String baseUrl) {
        DingTalkClient clientDingTalkClient2 = new DefaultDingTalkClient(baseUrl+DingTalkConstants.GET_USER_INFO);
        OapiV2UserGetRequest reqGetRequest = new OapiV2UserGetRequest();
        reqGetRequest.setUserid(userId);
        reqGetRequest.setLanguage(DingTalkConstants.REQUEST_LANGUAGE_CN);
        try {
            OapiV2UserGetResponse rspGetResponse = clientDingTalkClient2.execute(reqGetRequest, token);
            if (rspGetResponse != null && rspGetResponse.isSuccess() && DingTalkConstants.RESPONSE_SUCCESS_CODE.equals(rspGetResponse.getErrorCode())) {
                return rspGetResponse.getResult();
            }
        } catch (ApiException e) {
            log.error("获取钉钉用户信息失败：{}", e);
        }
        return null;
    }
}
